Отражение может также использоваться для реализации динамического связывания. Динамическое связывание состоит в том, что метод, который нужно вызвать, определяется в процессе выполнения, а не на этапе компиляции. Это один из примеров того, как метаданные используются для предоставления функциональных возможностей. Предыдущий пример демонстрирует, как получить сигнатуру метода, связанного с типом. Объект Methodlnf о содержит все необходимые метаданные для метода класса. Пример Dynamic (Динамический) демонстрирует очень простой случай динамического связывания.
Мы динамически загружаем сборку и получаем метаданные для метода определенного типа:
// Загрузить (Load) сборку Customer (Клиент)
Assembly *a = Assembly::Load("Customer") ;
// Загрузка ("Клиент")
// Получить метаданных для класса Customers (Клиенты)
// и одного метода
Type *t = a->GetType("01.NetCpp.Acme.Customers");
Вот что следует помнить программистам при программировании на C++. Работая со строками, которые содержат пространства имен или классы, необходимо использовать должным образом отформатированные строки, которые понятны методам класса отражения. Например, полностью определенное имя класса в вышеописанном коде — OI.NetCpp.Acme.Customers, а не OI::NetCpp::Acme::Customers, отформатированное в стиле C++. Таким образом, используемый формат подобен формату в С#, а не в C++.
Применяя классы отражения, мы могли бы сделать все это полностью динамически, произвольно выбирая типы, методы, и конструкторы из сборки Customer (Клиент), используя методы последнего примера, но мы хотели сохранить пример Dynamic (Динамический) простым. Более честолюбивая программа могла бы делать что-нибудь гораздо более интересное, вроде реализации декомпилятора сборки, который непосредственно из откомпилированной сборки генерирует исходный текст на управляемом C++, С#илиУВ.НЕТ.
Пространство имен System (Система) содержит класс Activator (Активатор, Модуль
активизации), в котором перегружается метод Createlnstance, предназначенный
для создания экземпляров любого типа .NET с помощью подходящего конструктора.
Класс Activator (Активатор, Модуль активизации) рассматривается в этой главе
в разделе, посвященном удаленному доступу. Чтобы создать экземпляр объекта Customers
(Клиенты), мы вызываем конструктор без параметров.
Type *t = a->GetType("01.NetCpp.Acme.Customers");
// Клиенты
Object *customerlnstance = // Объект
Activator::Createlnstance(t); // Активатор
Затем, чтобы вызвать метод GetCustomer, формируем список параметров и используем
метод Invoke (Вызвать) экземпляра Methodlnfо.
Dynamic\Customer\Debug в папку DynamicXDebug перед выполнение Dynamic . ехе.
// вызвать метод
Object *arguments [] = new Object*[1]; // новый Объект
int customerld = -1;
arguments[0] = _box(customerld); // параметры
Object *returnType = mi->Invoke( // Вызвать
customerlnstance, arguments); // параметры
Используя методы отражения, мы получаем информацию о типе для каждого поля в возвращаемой структуре. Обратите внимание, что метод GetValue, принадлежащий Fieldlnf о, возвращает данные для конкретного поля в объекте.
if (returnType->GetType() ==
Type::GetType("System.Collections.ArrayList"))
// ("Система.Коллекции.Список массивов")
{
ArrayList *arrayList =
dynamic_cast<ArrayList *>(returnType);
for (int i = 0; i<arrayList->Count; i++) // Счет
{
Type *itemType =
arrayList->get_Item(i)->GetType();
Fieldlnfo *fi [] = itemType->GetFields();
for (int j = 0; j < fi->Length; j++)
{
Object *fieldValue = // Объект
fi[j]->GetValue(arrayList->get_Item(i));
Console::Write( // Запись
"{0, -10} = {1, -15}",
fi[j]->Name, fieldValue); // Имя
}
Console::WriteLine();
}
}
Снова обращаем внимание на то, что в строке System.Collections.ArrayList (Система.Коллекции.Список массивов) для отделения имен использованы точки, а не "двойные двоеточия.
В этом коде не использованы никакие определенные объекты или типы из сборки Customer (Клиент). С целью проиллюстрировать главные принципы, мы применили некоторые знания о сборке, чтобы код был простым. Однако должно быть понятно, как сделать его полностью общим.
Можно сделать шаг вперед и использовать классы, которые генерируют метаданные (в System: :Reflection: :Emit (Система-Отражение-Генерация)). Можно даже динамически создавать сборку в памяти, а затем загружать и выполнять ее!